<?php

namespace App\Models\Traits;

use App\Models\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;

trait HasUserCache
{
	public static function sMyPayCodeTryCacheKey($id): string
	{
		return "user_{$id}_pay_code_try";
	}

	public static function sInfoCacheKey($id): string
	{
		return "user_{$id}_info";
	}

	public static function sGetCache($id)
	{
		if (! Redis::exists(self::sInfoCacheKey($id))) {
			if ($user = self::find($id)) {
				$user->addToCache();
				Log::debug("User: {$user->id} first cached");
			}
		}
		return Redis::hGetAll(self::sInfoCacheKey($id));
	}



	/*==================================================================================================================*/


	public function myPayCodeTryCacheKey(): string
	{
		return self::sMyPayCodeTryCacheKey($this->id);
	}

	public function infoCacheKey(): string
	{
		return self::sInfoCacheKey($this->id);
	}

	public function cacheFields(): array
	{
        $user = $this;

		return [
			'id' => $user->id,
			'parent_id' => $user->parent_id,
			'grade' => $user->grade,
			'invite_code' => $user->invite_code,
			'invite_string' => $user->inviteString(),

			'name' => $user->name ?? '',
			'nickname' => $user->nickname ?? '',
			'phone' => $user->phone ?? '',
			'signature' => $user->signature ?? '',
			'avatar_url' => img_path($user->avatar),
			'gender' => $user->gender ?? '',
			'birthday' => $user->birthday ?? '',
			'dividend_all' => $user->dividend_all,
			'dividend_day' => $user->dividend_day,
			'is_phone_bound' => $user->isPhoneBound(),
			'is_weixin_bound' => $user->isWeixinBound(),
			'is_weimini_bound' => $user->isWeiminiBound(),
			'is_alipay_bound' => $user->isAlipayBound(),
			'wx_nickname' => $user->wx_nickname ?? '',
			'wx_headimgurl' => $user->wx_headimgurl ?? '',
			'alipay_nickname' => $user->alipay_nickname ?? '',
			'alipay_avatar' => $user->alipay_avatar ?? '',
			'alipay_user_no' => $user->alipay_user_no ?? '',
			'is_new' =>$user->is_new ?? 1,
			'is_paying' => false,

			'created_at' => (string)$user->created_at,
		];
	}

	public function addToCache()
	{
		$data = $this->cacheFields();

		Redis::transaction(function () use ($data) {
			Redis::hMSet($this->infoCacheKey(), $data);
			Redis::expire($this->infoCacheKey(), cache_time());
		});
	}

	public function getCache()
	{
		if (! Redis::exists($this->infoCacheKey())) {
			$this->addToCache();
		}
		return Redis::hGetAll($this->infoCacheKey());
	}

	public function delFromCache()
	{
		Redis::del($this->infoCacheKey());
	}

	public function todayBonusTop100FromCache()
	{
		$key = "today_bonus_rank";
		return Cache::remember($key, 60, function () {
			return $this->dayBonusTop100();
		});
	}

	public function allBonusTop100FromCache()
	{
		$key = "all_bonus_rank";
		return Cache::remember($key, 60, function () {
			return $this->allBonusTop100();
		});
	}

	public function dayBonusRank($index = 0): array
	{
		$users = collect();

		$limit = $index + 9;
		$index = $index > 0 ? $index+1 : $index;

		$top100 = $this->todayBonusTop100FromCache();

		$mineId = $this->id;
		$mineRank = $top100->contains($mineId) ? $top100->search($mineId)+1 : 0;

		foreach ($top100 as $k => $id) {
			if ($k >= $index and $k <= $limit) {
				$users->push(self::sGetCache($id));
			}
		}

		return ['mine' => (int)$mineRank, 'day' => $users];
	}

	public function allBonusRank($index = 0): array
	{
		$users = collect();

		$limit = $index + 9;
		$index = $index > 0 ? $index+1 : $index;

		$top100 = $this->allBonusTop100FromCache();

		$mineId = $this->id;
		$mineRank = $top100->contains($mineId) ? $top100->search($mineId)+1 : 0;

		foreach ($top100 as $k => $id) {
			if ($k >= $index and $k <= $limit) {
				$users->push(self::sGetCache($id));
			}
		}

		return ['mine' => (int)$mineRank, 'all' => $users];
	}

	public function myTeamMembers()
	{
		$scope = request('scope');

		$key = url()->full();
		$key = "{$key}-user-{$this->id}-{$scope}-teams";

		return Cache::remember($key, 60, function () use ($scope) {
			return $this->myDownOneChildrenWithRecord($scope)
				->orderBy('parent_id')
				->orderByDesc('today_record_price')
				->orderByDesc('id')
				->paginate();
		});
	}

	public function myPayCodeTryCache(): int
	{
		$key = $this->myPayCodeTryCacheKey();

		if ($try = Redis::get($key)) {
			return (int)$try;
		} else {
			Redis::set($key, 0);
			$try = Redis::get($key);
			return (int)$try;
		}
	}

	public function leftPayCodeTryAfterError(): int
	{
		$payCodeTry = $this->myPayCodeTryCache() + 1;
		$payCodeTry = $payCodeTry <= 3 ? $payCodeTry : 3;
		Redis::set($this->myPayCodeTryCacheKey(), $payCodeTry);
		$leftChance = 3 - $payCodeTry;
		return $leftChance;
	}

	public function resetPayCodeTry()
	{
		$try = $this->myPayCodeTryCache();

		if ($try <= 0) return;

		Redis::set($this->myPayCodeTryCacheKey(), 0);
	}
}
